//////////////////////////////////////////////////////////////////////
// Reg.cpp: implementation of the CReg class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Reg.h"


//=======================================================================
//Macro define
#define MyFree(p)            { if(p) LocalFree(p); }
//=======================================================================
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////


//-------------------------------------------------------------------
//Description:
//    Construction and open the key
//-------------------------------------------------------------------
CReg::CReg()
{
	m_hKey = NULL;
	m_Index = 0;
	m_lpbValue = NULL;
}

//-------------------------------------------------------------------
//Description:
//    Construction and open the key
//
//Parameters:
//    hkRoot: [in] The root key
//    pszKey: [in] The key to open
//-------------------------------------------------------------------
CReg::CReg(HKEY hkRoot, LPCTSTR pszKey)
{
	m_hKey = NULL;
	m_Index = 0;
	m_lpbValue = NULL;
	Open(hkRoot, pszKey);
}

//-------------------------------------------------------------------
//Description:
//    Destruction
//-------------------------------------------------------------------
CReg::~CReg()
{
	if(m_hKey)
	{
		RegCloseKey(m_hKey);
	}
	MyFree(m_lpbValue);
}


//-------------------------------------------------------------------
//Description:
//    This function creates the specified key. 
//If the key already exists in the registry, the function opens it.
//After succeed in calling the fuction,should call the Reset() to release the resource.
//
//Parameters:
//    hkRoot: [in] The root key
//    pszKey: [in] The key to create
//-------------------------------------------------------------------
BOOL CReg::Create(HKEY hkRoot, LPCTSTR pszKey)
{
	DWORD dwDisp;
	return ERROR_SUCCESS == RegCreateKeyEx(hkRoot, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &m_hKey, &dwDisp);
}


//-------------------------------------------------------------------
//Description:
//    This function opens the specified key.
//After succeed in calling the fuction,should call the Reset() to release the resource.
//
//Parameters:
//    hkRoot: [in] The root key
//    pszKey: [in] The key to open
//    sam: [in] Not supported; set to 0
//-------------------------------------------------------------------
BOOL CReg::Open(HKEY hkRoot, LPCTSTR pszKey, REGSAM sam)
{
	return ERROR_SUCCESS == RegOpenKeyEx(hkRoot, pszKey, 0, sam, &m_hKey);
}

//-------------------------------------------------------------------
//Description:
//    Reset the value and release the resource.
//-------------------------------------------------------------------
void CReg::Reset()
{
	if(m_hKey)
	{
		RegCloseKey(m_hKey); 
	}
	MyFree(m_lpbValue);
	m_hKey = NULL;
	m_Index = 0;
	m_lpbValue = NULL;
}

//-------------------------------------------------------------------
//Description:
//    Operator overload
//-------------------------------------------------------------------
CReg::operator HKEY()
{
	return m_hKey;
}

//-------------------------------------------------------------------
//Description:
//    Check whether is ready for next operate
//
//Return value:
//    TRUE : Ready to do next operate
//    FALSE: Not ready.
//-------------------------------------------------------------------
BOOL CReg::IsOK()
{
	return m_hKey != NULL;
}


//-------------------------------------------------------------------
//Description:
//    This function enumerates subkeys of the specified open registry key.
//
//Parameters:
//    psz: [out] Pointer to a buffer that receives the name of the subkey, including the terminating null character. 
//        The function copies only the name of the subkey, not the full key hierarchy, to the buffer.
//    dwLen: [in]  Specifies the length of the buffer pointed to by the psz parameter.
//-------------------------------------------------------------------
BOOL CReg::EnumKey(LPTSTR psz, DWORD dwLen)
{
	if(!m_hKey)
	{
		return FALSE;
	}
	dwLen *= sizeof(TCHAR);
	return ERROR_SUCCESS == RegEnumKeyEx(m_hKey, m_Index++, psz, &dwLen, NULL, NULL, NULL, NULL);
}


//-------------------------------------------------------------------
//Description:
//    This function enumerates the values for the specified open registry key.
//
//Parameters:
//    pszName: [out] Pointer to a buffer that receives the name of the value, including the terminating null character. 
//    dwLenName: [in] Specifies the length of the buffer pointed to by the pszName parameter. 
//    lpValue: [out] Pointer to a buffer that receives the data for the value entry. This parameter can be NULL if the data is not required. 
//    dwLenValue: [in] Specifies the length of the buffer pointed to by the lpValue parameter. 
//-------------------------------------------------------------------
BOOL CReg::EnumValue(LPTSTR pszName, DWORD dwLenName, LPBYTE lpValue, DWORD dwLenValue)
{
	DWORD dwType;

	if(!m_hKey) 
	{
		return FALSE;
	}

	dwLenValue *= sizeof(BYTE); // convert length in number to bytes

	return ERROR_SUCCESS == RegEnumValue(m_hKey, m_Index++, pszName, &dwLenName, NULL, &dwType, (LPBYTE)lpValue, &dwLenValue);
}


//--------------------------------------------------------------------------------------------------------------
//Description:
//    Get the string value
//
//Parameters:
//    szName: [in] Pointer to a string containing the name of the value to query
//    szValue: [out] Pointer to a buffer that receives the value's data. 
//                If it's null, it will return the size of buffer need.
//    dwLen: [in] Specifies the length of the buffer pointed to by the szValue parameter. 
//                If szValue is null, the parameter would ignore.
//
//Return value:
//    The number of the characters have been get.
//0 means failed. Others means succeed, and the value include the null character
//----------------------------------------------------------------------------------------------------------------------
DWORD CReg::GetValueSZ(LPCTSTR szName, LPTSTR szValue, DWORD dwLen)
{
	if(!m_hKey)
	{
		return FALSE;
	}

	dwLen *= sizeof(TCHAR); // convert length in chars to bytes

	DWORD dwType ;
	if(ERROR_SUCCESS == RegQueryValueEx(m_hKey, szName, NULL, &dwType, (LPBYTE)szValue, &dwLen))
	{
		if(REG_SZ != dwType)
		{
			dwLen = 0;
			return FALSE;
		}
		else
		{
			dwLen /= sizeof(TCHAR);
		}

	}
	else
	{
		dwLen = 0;
	}

	return dwLen;
}

//-------------------------------------------------------------------
//Description:
//    Get the binary value
//
//Parameters:
//    szName: [in] Pointer to a string containing the name of the value to query
//    lpbValue: [out] Pointer to a buffer that receives the value's data.
//                If it's null, it will return the size of buffer need.
//    dwLen: [in] Specifies the length of the buffer pointed to by the lpbValue parameter. 
//                If szValue is null, the parameter would ignore.
//
//Return value:
//    The number of the binary have been get.
//0 means failed. Others means succeed, and the value include the null character
//-------------------------------------------------------------------
DWORD CReg::GetValueBinary(LPCTSTR szName, LPBYTE lpbValue, DWORD dwLen)
{
	if(!m_hKey) 
	{
		return FALSE;
	}


	DWORD dwType ;
	if(ERROR_SUCCESS == RegQueryValueEx(m_hKey, szName, NULL, &dwType, lpbValue, &dwLen))
	{
		if(dwType != REG_BINARY)
		{
			dwLen = 0;
		}
	}
	else
	{
		dwLen = 0;
	}

	return dwLen;

}



//-------------------------------------------------------------------
//Description:
//    Get the DWORD value
//
//Parameters:
//    szName:[in] The value of registry
//    dwDefault:[in] The default value return when failed in getting the DWORD value.
//
//Return value:
//    If the return value just be same as the dwDefault, it may mean failed.
//-------------------------------------------------------------------
DWORD CReg::GetValueDW(LPCTSTR szName, DWORD dwDefault)
{
	if(!m_hKey) 
	{
		return FALSE;
	}
	DWORD dwValue = dwDefault;
	DWORD dwLen = sizeof(DWORD);
	DWORD dwType;
	if(ERROR_SUCCESS == RegQueryValueEx(m_hKey, szName, NULL, &dwType, (LPBYTE)&dwValue, &dwLen))
	{
		if(dwType != REG_DWORD)
		{
			dwValue = dwDefault;
		}
	}
	else
	{
		dwValue = dwDefault;
	}

	return dwValue;
}


//-------------------------------------------------------------------
//Description:
//    Set the string value
//
//Parameters:
//    szName: [in] Pointer to a string containing the name of the value to set
//    szValue: [in] The buffer include the data to be set
//    dwLen: [in] Specifies the length of the buffer pointed to by the szValue parameter.  
//-------------------------------------------------------------------
BOOL CReg::SetSZ(LPCTSTR szName, LPCTSTR szValue, DWORD dwLen)
{
	//Prefix
	if(!m_hKey) 
	{
		return FALSE;
	}

	return ERROR_SUCCESS == RegSetValueEx(m_hKey, szName, 0, REG_SZ, (LPBYTE)szValue, sizeof(TCHAR)*dwLen);
}


//-------------------------------------------------------------------
//Description:
//    Set the string value
//
//Parameters:
//    szName: [in] Pointer to a string containing the name of the value to set
//    szValue: [in] The string buffer include null character to be set 
//-------------------------------------------------------------------
BOOL CReg::SetSZ(LPCTSTR szName, LPCTSTR szValue)
{
	return SetSZ(szName, szValue, 1 + _tcslen(szValue));
}


//-------------------------------------------------------------------
//Description:
//    Get the DWORD value
//
//Parameters:
//    szName: [in] Pointer to a string containing the name of the value to set
//    dwValue: [in] The value to be set
//-------------------------------------------------------------------
BOOL CReg::SetDW(LPCTSTR szName, DWORD dwValue)
{
	//Prefix
	if(!m_hKey) 
	{
		return FALSE;
	}

	return ERROR_SUCCESS==RegSetValueEx(m_hKey, szName, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
}


//-------------------------------------------------------------------
//Description:
//    Get the binary value
//
//Parameters:
//    szName: [in] Pointer to a string containing the name of the value to set
//    lpbValue: [in] The buffer include the data to be set
//    dwLen: [in] Specifies the length of the buffer pointed to by the lpbValue parameter.
//-------------------------------------------------------------------
BOOL CReg::SetBinary(LPCTSTR szName, LPBYTE lpbValue, DWORD dwLen)
{
	//Prefix
	if(!m_hKey) 
	{
		return FALSE;
	}

	return ERROR_SUCCESS == RegSetValueEx(m_hKey, szName, 0, REG_BINARY, lpbValue, sizeof(BYTE) * dwLen);
}


//-------------------------------------------------------------------
//Description:
//    Set the Multi value
//
//Parameters:
//    szName: [in] Pointer to a string containing the name of the value to set
//    lpszValue: [in] The buffer include the data to be set
//    dwLen: [in] Specifies the length of the buffer pointed to by the lpszValue parameter.
//-------------------------------------------------------------------
BOOL CReg::SetMultiSZ(LPCTSTR szName, LPCTSTR lpszValue, DWORD dwLen)
{
	return ERROR_SUCCESS == RegSetValueEx(m_hKey, szName, 0, REG_MULTI_SZ, (LPBYTE)lpszValue, sizeof(TCHAR)*dwLen);
}


//-------------------------------------------------------------------
//Description:
//    This function removes a named value from the specified registry key.
//
//Parameters:
//    szName:[in] Pointer to a null-terminated string that names the value to remove.
//-------------------------------------------------------------------
BOOL CReg::DeleteValue(LPCTSTR szName)
{
	//Prefix
	if(!m_hKey) 
	{
		return FALSE;
	}
	//
	return ERROR_SUCCESS == RegDeleteValue(m_hKey, szName);
}



//-------------------------------------------------------------------
//Description:
//    This function recursively deletes all subkeys of a named subkey of a specified registry key.
//
//Parameters:
//    szName:[in] Pointer to a null-terminated string specifying the name of the key to delete. This parameter cannot be NULL. 
//-------------------------------------------------------------------
BOOL CReg::DeleteKey(LPCTSTR szName)
{
	if(!m_hKey) 
	{
		return FALSE;
	}

	return ERROR_SUCCESS == RegDeleteKey(m_hKey, szName);
}


//-------------------------------------------------------------------
//Description:
//    Get the value type
//
//Parameters:
//    szName: [in] Pointer to a null-terminated string that names the value
// 
//------------------------------------------------------------------------
ValueType CReg::GetValueType(LPCTSTR szName)
{
	if(m_hKey == NULL)
	{
		return VAL_ERROR;
	}

	DWORD dwType ;
	if(ERROR_SUCCESS != RegQueryValueEx(m_hKey, szName, NULL, &dwType, 0, 0))
	{
		return VAL_ERROR;
	}


	switch(dwType)
	{
	case REG_BINARY:
		return VAL_BINARY;

	case REG_DWORD:
	case REG_DWORD_BIG_ENDIAN:
		return VAL_DWORD;

	case REG_EXPAND_SZ:
	case REG_SZ:
		return VAL_SZ;

	case REG_MULTI_SZ:
		return VAL_MULTISZ;

	default:
		return VAL_ERROR;    // There are other types, but not supported by CReg
	}
}


//-------------------------------------------------------------------
//Description:
//    Check the key exist.
//
//Parameters:
//    pszKey: [in] Pointer to a null-terminated string that names key
// 
//------------------------------------------------------------------------
BOOL CReg::CheckKeyExist(HKEY hkRoot,LPCTSTR pszKey)
{
	HKEY hKey = 0;
	if(ERROR_SUCCESS == RegOpenKeyEx(hkRoot, pszKey, 0, 0, &hKey))
	{
		RegCloseKey(hKey);
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}
